/* eslint-disable */
import Layers from "../../lang/layers";
import FormInput from "./form-input";
import Asserts from "@/lang/core/asserts.js";
import FormWrapper from "./form-wrapper";

/**
 * 默认的触发器
 *
 * 一个全局的 change() 事件
 *
 * @param name  字段名
 * @param value 值
 */
const trigger = (name, value) => {
}


/**
 * 表单组
 *
 * 内部已经包含完整的调用逻辑，只需要根据提供的数据，渲染界面即可。
 *
 * 设计思路，类似于后台的 MVC 模式，form-model => form-input => view；
 *
 * vue 环境的问题：
 * 表单构建和序列化过程，是有严格顺序的，但是表单组件的渲染，是异步执行的，默认情况下，首次序列化表单，很容易产生空指针异常。
 * 比如：一个组件包含一个表单和一个表格，载入表格的时候，需要进行首次加载，这时候必须控制表单先完成初始化。
 * 因此，我们直接放弃在 vue 中写逻辑的打算，
 */
class FastForm {
    /**
     * 根据数据模型，创建一个表单对象
     *
     * @param models {{}|[]}
     */
    constructor(models) {
        /**
         * form-input 列表
         *
         * @type {[FormInput]}
         */
        this.group = [];

        /**
         * 验证规则，表单数据的校验规则
         *
         * @type {{}}
         */
        this.rules = {}

        /**
         * 风格主题
         *
         * 组件会根据这个值，进行不同的风格绘制，常见的，就是水平布局和垂直布局
         *
         * @type {string}
         */
        this.theme = '';
        /**
         * 表单初始值
         *
         * @type {{}}
         */
        this.default_value = {}

        /**
         * 值变化触发器
         *
         * 如果有必要，子组件可以通过当前函数，通知到表单主体
         * （暂时取消这一设计）
         *
         * @type {function}
         * @param name  键
         * @param value 值
         */
        this.trigger = trigger;

        // 根据数据模型，转换成 FormInput 列表
        if (models !== undefined) {
            this.setModels(models);
        }
    }

    /**
     * 设置只变化侦听事件
     *
     * @param listener {function} 侦听函数
     */
    setValueChangeListener(listener) {
        Asserts.isTypeOf(listener, 'function', 'listener is not a function!')
        this.trigger = listener
    }

    /**
     *设置对象模型
     *
     * @param models {{}|[]} 允许是对象或者数组
     */
    setModels(models) {
        let ret = [];

        if (Array.isArray(models)) {
            // 表单模型树一个数组
            models.forEach(item => {
                const input = new FormInput();

                // 复制同名字段到 input
                input.from(item);

                // 所属表单
                input.form = this;
                // 风格主题
                input.theme = this.theme;

                ret.push(input);

                // 表单校验规则
                if (input.rules !== undefined) {
                    this.rules[input.name] = input.rules;
                }

                // 默认值
                if (input.value !== undefined) {
                    this.default_value[input.name] = input.value;
                }
            });
        } else {
            // 表单模型是一个对象
            for (let key in models) {
                if (models.hasOwnProperty(key)) {
                    const input = new FormInput();

                    input.name = key;
                    input.value = models[key];

                    ret.push(input);

                    // 默认值
                    if (input.value !== undefined) {
                        this.default_value[input.name] = input.value;
                    }
                }
            }
        }
        this.group = ret;
    }


    /**
     * 获取所有输入框对象实例
     *
     * @returns {[FormInput]} 实例列表
     */
    getGroups() {
        return this.group;
    }

    /**
     * 获取表单输入框实例
     *
     * @param name 输入框名称
     * @returns {FormInput} 实例
     */
    getFormInput(name) {
        for (let i = 0; i < this.group.length; i++) {
            console.log(this.group[i].name)
            if (name === this.group[i].name) {
                return this.group[i];
            }
        }
        throw new NullPointerException('form input is undefined:' + name);
    }

    /**
     * 覆盖表单数值
     *
     * 设值过程中，会触发 change() 事件；未指定的值，仍然使用之前的值。
     *
     * @param obj {{}} 对象
     */
    recover(obj) {
        //根据序列化之后的值，进行数据恢复
        for (let i = 0; i < this.group.length; i++) {
            let input = this.group[i];
            let val = obj[input.name];
            if (val !== undefined && input.value !== val) {
                input.changeValue(val);
            }
        }
    }

    /**
     * 表单设值
     *
     * 设值过程中，会触发 change() 事件；未指定的值，会用缺省值替换。
     *
     * @param obj {{}} 对象
     */
    val(obj) {
        for (let i = 0; i < this.group.length; i++) {
            let input = this.group[i];
            if (input.active) {
                let val = obj[input.name];
                if (val === undefined) {
                    val = input.defaultValue;
                }
                if (input.value !== val) {
                    input.changeValue(val);
                }
            }
        }
    }

    /**
     * 设置新的表单数值
     *
     * 但是不触发监听事件
     */
    setValue(name, value) {
        let input = this.getFormInput(name);
        input.setValue(value);
    }

    /**
     * 设置新的表单数值
     *
     * 但是不触发监听事件
     */
    changeValue(name, value) {
        let input = this.getFormInput(name);
        input.changeValue(value);
    }

    /**
     * 设置初始值
     *
     * @param obj
     */
    setDefaultValue(obj) {
        this.default_value = obj;
    }

    /**
     * 重置表单
     */
    reset() {
        this.val(this.default_value);
    }

    /**
     * 置空表单
     */
    clear() {
        for (let i = 0; i < this.group.length; i++) {
            this.group[i].clear();
        }
    }

    /**
     * 设置校验规则
     *
     * @param rules {{}}
     */
    setRules(rules) {
        this.rules = rules;
    }

    /**
     * 设置校验规则
     *
     * @param name {String}
     * @param rules {{}}
     */
    addRules(name, rules) {
        this.rules[name] = rules;
    }

    /**
     * 设置校验规则
     * @returns {boolean} 是否满足验证结果
     */
    isValid() {
        for (let i = 0; i < this.group.length; i++) {
            let ele = this.group[i];
            // 如果isValid未定义，则说明没用到表单验证，直接校验通过
            if (!ele.isValid()) {
                console.error('invalid: ' + ele.label);
                console.error('invalid: ' + ele.message);
                return false;
            }
        }
        return true;
    }


    /**
     * 序列化表单
     *
     * @returns {{}} 表单数值
     */
    serialize() {
        let res = {};
        for (let i = 0; i < this.group.length; i++) {
            let input = this.group[i];
            let val = input.getFormatValue();

            // 序列化结果过滤无意义的值
            if (Layers.isNotEmpty(val)) {
                res[input.name] = val;
            }
        }
        return res;
    }

    /**
     * 序列化表单
     *
     * @returns {{}} 表单数值
     */
    formData() {
        let res = new FormData();
        for (let i = 0; i < this.group.length; i++) {
            let input = this.group[i];
            let val = input.getFormatValue();

            // 序列化结果过滤无意义的值
            if (Layers.isNotEmpty(val)) {
                res.append(input.name, val);
            }
        }
        return res;
    }
}

export const InputType = {
    // 文本输入
    Number: 'Number',

    // 字符输入：文本框、文本域、富文本框
    Textarea: 'Textarea',
    TextView: 'TextView',
    Editor: 'Editor',

    // 布尔输入：开关、单选框
    Switch: 'Switch',
    Checkbox: 'Checkbox',

    // 原样输入，需要手动处理数据格式
    Select: 'Select',
    RadioGroup: 'RadioGroup',

    // 数组输入：复选框组
    CheckboxGroup: 'CheckboxGroup',

    // 日期选择
    DateRange: 'DateRange',
    DatePicker: 'DatePicker',
    DatetimeRange: 'DatetimeRange',
    DatetimePicker: 'DatetimePicker',

    // 文件上传
    File: 'File',
    Image: 'Image',
    Uploader: 'Uploader',

    // 树形选择
    CheckTree: 'CheckTree',
    SelectTree: 'SelectTree'
}

export default FastForm